package com.atguigu.tingshu.user.receiver;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.user.service.MqOpsService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Around;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * Description:
 *
 * @author Yanxinhao on 2025/2/13
 */
@Component
@Slf4j
public class UserInfoReceiver {

    @Autowired
    private MqOpsService mqOpsService;

    @Autowired
    private StringRedisTemplate redisTemplate;



    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_USER_PAY_RECORD,durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_USER),
            key = MqConst.ROUTING_USER_PAY_RECORD))
    @SneakyThrows //在编译期间忽略掉异常，在执行过程中如果有异常，那么就会抛出异常
    public void listenUpdatePayRecord(String context, Message message, Channel channel){
        //1.若传来的消息为空，那么就没有必要继续执行
        if (StringUtils.isEmpty(context)){
            return;
        }
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        //2.将传来的JSON消息反序列化为UserPaidRecordVo对象
        UserPaidRecordVo userPaidRecordVo = JSONObject.parseObject(context, UserPaidRecordVo.class);
        try {
            //3. 消费消息 如果消费期间发生异常会抛出GuiguException
            mqOpsService.updateUserPaidRecord(userPaidRecordVo);

            //4.消费完消息了，进行手动应答  如果应答期间发生异常会抛出Exception
            channel.basicAck(deliveryTag,false);

            //抛出的异常交由下方捕获机制来选择进行重试或是丢弃
        } catch (GuiguException e) {

            //5.重试机制，通过redis来记录重试次数
            String retryMsgKey = "retry:msg:" + context;
            Long count = redisTemplate.opsForValue().increment(retryMsgKey);
            //我们选择重试3回，给三次机会，如果超过3次就选择不重试
            if (count >= 3){
                log.error("消息重试了{}次,异常原因:{},交由人工排查",count,e.getMessage());
                channel.basicNack(deliveryTag,false,false);
            } else {
                log.error("消息第{}次重试",count);
                channel.basicNack(deliveryTag,false,true);
            }

        } catch (Exception e){
            log.error("消息手动应答期间，可能由于网络波动应答失败，但是消息已经消费成功，丢弃消息");
            channel.basicNack(deliveryTag,false,false);
        }


    }
}